﻿using System;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;

namespace Scrabble.Controls
{
    public class BlockGauge : Control
    {
        public static readonly DependencyProperty ValueProperty = DependencyProperty.Register("Value", typeof(int), typeof(BlockGauge),
            new FrameworkPropertyMetadata(-1, FrameworkPropertyMetadataOptions.AffectsRender | FrameworkPropertyMetadataOptions.AffectsMeasure));

        public static readonly DependencyProperty MaximumProperty = DependencyProperty.Register("Maximum", typeof(int), typeof(BlockGauge),
            new FrameworkPropertyMetadata(10, FrameworkPropertyMetadataOptions.AffectsRender | FrameworkPropertyMetadataOptions.AffectsMeasure));

        public static readonly DependencyProperty BlockWidthProperty = DependencyProperty.Register("BlockWidth", typeof(int), typeof(BlockGauge),
            new FrameworkPropertyMetadata(10, FrameworkPropertyMetadataOptions.AffectsRender | FrameworkPropertyMetadataOptions.AffectsMeasure));

        public static readonly DependencyProperty GapWidthProperty = DependencyProperty.Register("GapWidth", typeof(int), typeof(BlockGauge),
            new FrameworkPropertyMetadata(2, FrameworkPropertyMetadataOptions.AffectsRender | FrameworkPropertyMetadataOptions.AffectsMeasure));

        public static readonly DependencyProperty FillProperty = DependencyProperty.Register("Fill", typeof(Brush), typeof(BlockGauge),
            new FrameworkPropertyMetadata(Brushes.DarkOrange, FrameworkPropertyMetadataOptions.AffectsRender));

        public static readonly DependencyProperty StrokeProperty = DependencyProperty.Register("Stroke", typeof(Pen), typeof(BlockGauge),
            new FrameworkPropertyMetadata(new Pen(Brushes.DarkOrange, 1), FrameworkPropertyMetadataOptions.AffectsRender));

        public int Value
        {
            get { return (int)GetValue(ValueProperty); }
            set { SetValue(ValueProperty, value); }
        }

        public int Maximum
        {
            get { return (int)GetValue(MaximumProperty); }
            set { SetValue(MaximumProperty, value); }
        }

        public int BlockWidth
        {
            get { return (int)GetValue(BlockWidthProperty); }
            set { SetValue(BlockWidthProperty, value); }
        }

        public int GapWidth
        {
            get { return (int)GetValue(GapWidthProperty); }
            set { SetValue(GapWidthProperty, value); }
        }

        public Brush Fill
        {
            get { return (Brush)GetValue(FillProperty); }
            set { SetValue(FillProperty, value); }
        }

        public Pen Stroke
        {
            get { return (Pen)GetValue(StrokeProperty); }
            set { SetValue(StrokeProperty, value); }
        }

        protected override Size MeasureOverride(Size constraint)
        {
            return new Size(BlockWidth * Maximum + GapWidth * Math.Max(0, Maximum - 1), double.IsPositiveInfinity(constraint.Height) ? BlockWidth : constraint.Height);
        }

        protected override void OnRender(DrawingContext drawingContext)
        {
            base.OnRender(drawingContext);

            if (Value == 0) return;

            var blockWidth = BlockWidth;
            var gapWidth = GapWidth;

            var bounds = new Rect(0, 0, blockWidth, blockWidth);

            switch (VerticalContentAlignment)
            {
                case VerticalAlignment.Bottom:
                    bounds.Offset(0, ActualHeight - bounds.Height);
                    break;

                case VerticalAlignment.Center:
                    bounds.Offset(0, (ActualHeight - bounds.Height) / 2);
                    break;

                case VerticalAlignment.Stretch:
                    bounds.Height = ActualHeight;
                    break;
            }

            if (SnapsToDevicePixels)
            {
                var thickness = Stroke != null ? Stroke.Thickness / 2 : 0;

                var guidelineSet = new GuidelineSet();

                guidelineSet.GuidelinesY.Add(bounds.Top + thickness);
                guidelineSet.GuidelinesY.Add(bounds.Bottom + thickness);

                var x = bounds.Left + thickness;

                for (var i = 0; i < Maximum; ++i)
                {
                    guidelineSet.GuidelinesX.Add(x);
                    guidelineSet.GuidelinesX.Add(x + blockWidth);

                    x += blockWidth + gapWidth;
                }

                drawingContext.PushGuidelineSet(guidelineSet);
            }

            for (var i = 0; i < Maximum; ++i)
            {
                drawingContext.DrawRectangle(i < Value ? Fill : null, Stroke, bounds);
                bounds.Offset(blockWidth + gapWidth, 0);
            }

            if (SnapsToDevicePixels)
            {
                drawingContext.Pop();
            }
        }
    }
}
